package com.zzzy.common.util;

import com.zzzy.common.exception.BusinessException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.Base64;

/**
 * 文件工具类，主要处理文件上传时类型的判断、以流的形式在页面显示图片等
 */
public class FileUtil {
    public static final String JPG = "jpg";
    public static final String PNG = "png";
    public static final String GIF = "gif";
    public static final String BMP = "bmp";
    public static final String DOC = "doc";
    public static final String DOCX = "docx";
    public static final String PDF = "pdf";
    public static final String XLS = "xls";
    public static final String XLSX = "xlsx";
    public static final String UNKNOWN = "unknown";

    /**
     * byte数组转换成16进制字符串
     * @param src
     * @return
     */
    private static String bytesToHexString(byte[] src){
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }


    /**
     * 根据文件流判断文件类型
     * @param fileBytes:文件字节流
     * @return jpg/png/unknown
     */
    public static String getFileType(byte[] fileBytes){
        //文件内容比较多时，读取文件的前几个字节来判断图片格式,避免文件过大转成base64时耗时太长
        //要截取的字节长度
        int iCount = 15;
        //截取的数组
        byte[] bs;
        if (fileBytes.length > iCount){
            bs = new byte[iCount];
            System.arraycopy(fileBytes, 0, bs, 0, iCount);
        }else{
            bs = fileBytes;
        }
        //获取文件类型的base64字符串
        String strType = bytesToHexString(bs).toUpperCase();
        if (strType.startsWith("FFD8FF")) {
            return JPG;
        } else if (strType.startsWith("89504E47")) {
            return PNG;
        } else if (strType.startsWith("47494638")) {
            return GIF;
        } else if (strType.startsWith("424D")) {
            return BMP;
        } else if (strType.startsWith("D0CF11E0")) {
            //近似匹配结构化文件，近似匹配 office文件（xls等不带x 扩展名的文件格式）
            return DOC;
        } else if (strType.startsWith("504B0304")) {
            //近似匹配 office 带有 x 扩展名的文件格式（不包括zip文件格式）
            return DOCX;
        } else if (strType.startsWith("255044462D")) {
            return PDF;
        } else{
            return UNKNOWN;
        }
    }

    /**
    * 文件是否被修改过扩展名
    */
    public static boolean isChangeFileExtendType(String fileName, byte[] fileBytes){
        String fileType = getFileType(fileBytes);
        String extendType = fileName.substring(fileName.lastIndexOf(".") +1);
        if (StringUtils.equalsIgnoreCase(DOC, fileType)){
            return !StringUtils.equalsIgnoreCase(extendType, DOC) && !StringUtils.equalsIgnoreCase(extendType, XLS);
        }
        if (StringUtils.equalsIgnoreCase(DOCX, fileType)){
            return !StringUtils.equalsIgnoreCase(extendType, DOCX) && !StringUtils.equalsIgnoreCase(extendType, XLSX);
        }
        return !StringUtils.equalsIgnoreCase(extendType, fileType);
    }

    /**
     * 判断文件是否为有效图片
     * @param fileBytes:文件字节流
     * @return
     */
    public static boolean checkIsImage(byte[] fileBytes) {
        String strFileType = getFileType(fileBytes);
        switch (strFileType){
            case "png" :
                return true;
            case "jpg" :
                return true;
            case "gif" :
                return true;
            case "bmp" :
                return true;
            default:
                return false;
        }
    }
    /**
     * 判断文件是否为有效图片
     * @param imageData
     * @return
     */
    public static boolean checkIsImage(String imageData){
        //处理base64，截取data:image/png;base64,后面的字符串
        String[] arrImgInfo = imageData.split(",");
        Base64.Decoder decoder = Base64.getDecoder();
        if (arrImgInfo.length < 2){
            throw new BusinessException("非有效图片");
        }
        byte[] byteImage = decoder.decode(arrImgInfo[1]);
        return checkIsImage(byteImage);
    }
    /**
     * 判断文件是否为有效PDF
     * @param fileBytes:文件字节流
     * @return
     */
    public static boolean checkIsPDF(byte[] fileBytes) {
        String strFileType = getFileType(fileBytes);
        switch (strFileType){
            case PDF:
                return true;
            default:
                return false;
        }
    }
    public static boolean checkIsWord(byte[] fileBytes){
        String fileType = getFileType(fileBytes);
        return StringUtils.equals(fileType, DOC) || StringUtils.equals(fileType, DOCX);
    }

    /**
     * 判断文件是否为有效附件
     * @param fileBytes:文件字节流
     * @return
     * @throws FileNotFoundException
     */
    public static boolean checkIsAtt(byte[] fileBytes) {
        String strFileType = getFileType(fileBytes);
        //jpg|.jpeg|.png|.bmp|.gif|.doc|.docx|.pdf
        switch (strFileType){
            case "png" :
                return true;
            case "jpg" :
                return true;
            case "gif" :
                return true;
            case "bmp" :
                return true;
            case DOC:
                return true;
            case DOCX:
                return true;
            case PDF:
                return true;
            default:
                return false;
        }
    }
    /**
     * 判断文件是否为有效合同
     * @param fileBytes:文件字节流
     * @return
     * @throws FileNotFoundException
     */
    public static boolean checkIsContract(byte[] fileBytes) {
        String strFileType = getFileType(fileBytes);
        switch (strFileType){
            case DOC:
                return true;
            case DOCX:
                return true;
            case PDF:
                return true;
            default:
                return false;
        }
    }

    /**
     * 在页面中以流的形式生成图片
     * @param response
     * @param strPath：图片路径
     * @throws IOException
     */
    public static void createImg(HttpServletResponse response, String strPath) throws IOException {
        //标识原始图片的二进制数组
        byte[] byteImage = null;
        //标识图片后缀名
        String strImgExt = "";
        FileInputStream fis = null;
        OutputStream os = null;

        //获取图片扩展名
        int index = strPath.lastIndexOf(".");
        strImgExt = strPath.substring(index + 1);

        fis = new FileInputStream(strPath);
        int fileSize = fis.available();
        byteImage = new byte[fileSize];
        fis.read(byteImage);
        //缩放图片
        response.setCharacterEncoding("UTF-8");
        //******读取磁盘文件，输出文件流 开始*******************************
        // application/x-excel, application/ms-powerpoint, application/pdf
        response.setContentType("image/" + strImgExt);
        //filename应该是编码后的(utf-8)
        response.setHeader("Content-Disposition", "attachment; filename=down." + strImgExt);
        response.setContentLength(fileSize);

        os = response.getOutputStream();
        os.write(byteImage);
        os.flush();
        response.flushBuffer();
        fis.close();
        os.close();
    }

    /**
     * 输出文件流
     * @param response
     * @param bytesFileBlob 文件二进制字节流
     * @param fileName 文件名
     * @throws IOException
     */
    public static void outputFileStream(HttpServletResponse response, byte[] bytesFileBlob, String fileName) {
        //文件扩展名
        String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
        //生成的文件类型
        String strContentType;
        if ((DOC.equalsIgnoreCase(fileExt)) || (DOCX.equalsIgnoreCase(fileExt))){
            strContentType = "application/msword";
        } else if ((XLS.equalsIgnoreCase(fileExt)) || (XLSX.equalsIgnoreCase(fileExt))){
            strContentType = "application/x-excel";
        } else if (PDF.equalsIgnoreCase(fileExt)){
            strContentType = "application/pdf";
        } else {
            strContentType = "image/" + getFileType(bytesFileBlob);
        }

        int fileSize = bytesFileBlob.length;
        response.reset();
        // application/x-excel, application/ms-powerpoint, application/pdf
        response.setContentType(strContentType);
        try {
            //fileName应该是编码后的(utf-8)
            response.setHeader("Content-Disposition","attachment; filename=" + URLEncoder.encode(fileName,"UTF-8"));
            response.setContentLength(fileSize);
            OutputStream outputStream = response.getOutputStream();
            outputStream.write(bytesFileBlob);
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
            throw new BusinessException("输出文件流输出文件流错误");
        }
        
    }
    /**
    * 获取resources目录下文件
    */
    public static byte[] getFileByteFromClassPath(String filePath){
        byte[] bytes;
        try (InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath)){
            bytes = IOUtils.toByteArray(inputStream);
        } catch (IOException e) {
            throw new BusinessException("读取文件失败");
        }
        return bytes;
    }

    public static byte[] toByteArray(InputStream inputStream) {
        byte[] bytes;
        byte[] buffer = new byte[1024];
        int bytesRead;
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream()){
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                bos.write(buffer, 0, bytesRead);
            }
            bytes = bos.toByteArray();
        } catch (IOException e) {
            throw new BusinessException("读取文件失败");
        }

        return bytes;
    }
}
